const cvs = document.querySelector('canvas');
const ctx = cvs.getContext("2d");


// TODO 
// # game plan
// create 3 states:
// ST.START
// ST.PLAY
// ST.END
//
// ST.START:
// - draw a text "Start", with black and white flashing
// - when user click any place OR key input any key
//   go to ST.PLAY
// - TODO select EASY, MEDIUM, HARD mode etc.
// 
// ST.PLAY:
// - generate a moving ball (red?) e.g. ball.radius = 30 (bigger, easy)
//   easy: ball move from left to right, along the middle of screen
//         ball disappears when it reaches the edge of screen
//   hard: ball move from any edge of screen, with random direction
//         ball disappears when it reaches the edge of screen
// NOTE: speed vx, vy is random, but reasonable, e.g. 
// ball starts from left edge, vx > 0 
//         
// - when user click on the ball, scores 1 point, ball disappears
// - after the ball disappears, another new ball appears at edge,
//   can give a small delay
// - when the ball is hit by user click, give a flash animation
//   to change the color of ball (red/yellow?)
// - play a sound when user click (miss.mp3),  play a different sound when 
//   the click hit the ball (hit.mp3) TODO
// - total 10 balls, max is 10 points, min is 0 points
// - draw the score on screen
// - when all 10 balls are finished (completely disappeared)
//   go to ST.END
//
// ST.END:  
// - if max scores, print "Perfect! score:10" and play win.mp3 audio
// - if scores >5 and score < 10, print "Good!  score:" + score
//   (no sound?)
// - if scores < 5, print "Bad", play bad sound (TODO)
// 
// 
// - Restart button in ST.PLAY and ST.END stage
//   when clicked, go to ST.START
//
// if needed, we can give another state ST.HIT to play the animation 
// when ball is hit.
const VX = 7;// speed in X direction
const MAX_BALL = 10;
const ST = {
    CHOOSE: 0,
    START: 1,
    PLAY: 2,
    END: 3,
}
const CHOOSE = {
    TIME: 1,
    COUNT: 2, 
}

let state = ST.CHOOSE;
let plus = undefined;
let raf = undefined;
let hitSound = new Audio('water.mp3');
let unHitSound = new Audio('error.mp3');
let score = 0;

class Choose{
    draw(){
        ctx.fillStyle = 'silver';
        ctx.fillRect(90, 65, 200, 50);
        ctx.fillRect(500, 65, 220, 50);
        ctx.font = '36px courier';
        ctx.fillStyle = 'green';
        ctx.fillText('时间 TIME', 100, 100);
        ctx.fillStyle = 'blue';
        ctx.fillText('数数 count', 510, 100);
    }
    onClick(x, y){
        if(x > 90 && x < 290 && y > 65 && y < 115){
            state = ST.START;
            plus = CHOOSE.TIME;
        }
        if(x > 500 && x < 720 && y > 65 && y < 115){
            state = ST.START;
            plus = CHOOSE.COUNT;
        }
    }
}
let chooseState = new Choose();

class Start{
    constructor(){
        this.counter = 0;
    }
    logic(){
        this.counter++;
    }
    draw(){
        ctx.clearRect(0, 0, cvs.clientWidth, cvs.clientHeight);
        ctx.fillStyle = 'silver';
        ctx.fillRect(90, 60, 160, 50);
        ctx.font = '48px courier';
        const FLASH = 16;
        if((this.counter & FLASH) == FLASH){
            ctx.fillStyle = 'silver';
        } else {
            ctx.fillStyle = 'black';
        }
        ctx.fillText('START', 100, 100);
    }
    onClick(x, y){
        if(x > 90 && x < 250 && y > 60 && y < 110){
            state = ST.PLAY;
        }
    }
}
let startState = new Start();

class Play{
    constructor(){
        this.color = 'red';
        this.X = 0;
        this.Y = Math.random()*500 + 200;
        this.VX = VX;
        this.score = 0;
        this.ball = 0;
        this.startTime = Date.now(); // time in millisecond
    }
    logic(){
        if (plus == CHOOSE.TIME && (Date.now() - this.startTime > (VX * 5 * 1000 + 10))) {
            state = ST.END;
            score = this.score;
            return; // early exit
        }
        this.X = this.X + this.VX;
        if(this.X >= cvs.clientWidth && plus == CHOOSE.TIME){
            this.X = 0;
            return;
        }
        if(this.X >= cvs.clientWidth && plus == CHOOSE.COUNT){
            this.ball++;
            this.X = 0;
            this.Y = Math.random()*500 + 200;
            if(this.ball >= MAX_BALL){
                state = ST.END;
                score = this.score;
            }
        }
    }
    draw(){
        ctx.clearRect(0, 0, cvs.clientWidth, cvs.clientHeight);
        ctx.fillStyle = this.color;
        ctx.fillRect(this.X, this.Y, 50, 50);
        ctx.font = '48px courier';
        ctx.fillStyle = 'black';
        let msg = 'Fraction : ' + this.score;
        if (plus == CHOOSE.TIME) {
            // mode 模式
            msg += ' time: ' + Math.floor((Date.now() - this.startTime) / 1000);
        }
        ctx.fillText(msg, 100, 100);
    }
    onClick(x, y){
        if(x > this.X && x < this.X + 50 && y > this.Y && y < this.Y + 50){
            hitSound.play();// play sound
            this.X = 0;
            this.Y = Math.random()*500 + 200;
            this.score ++;
            this.ball ++;
            draw();
            console.log('play.onClick() this.ball=', this.ball);
            if(this.ball >= MAX_BALL){
                state = ST.END;
                score = this.score;
            }
        }else{
            unHitSound.play();
        }
    }
}
let playState = new Play(); 

class End{
    // constructor / init
    // init(score) - if score == 10 ... , this.result = RE.PERFECT
    // if ..., this.result = RE.GOOD,  ... if ... this.result = RE.EFFORT
    // const RE {
    //   PERFECT: 0,....
    // }
    //
    // draw() switch (this.result) case PERFECT ...  case GOOD ...

    logic(){
        // if(score == 10 && plus == CHOOSE.COUNT){
        //     drawWin('perfect');
        //     return;
        // }
        // if(score >=7 && score < 10 && plus == CHOOSE.COUNT){
        //     drawWin('good');
        //     return;
        // }
        // if(score < 7 && plus == CHOOSE.COUNT){
        //     drawWin('effort');
        //     return;
        // }

        if (score >= 10) {
            drawWin('完美! perfect');
            return;
        }
        if (score >= 7 && score < 10) {
            drawWin('好! good');
            return;
        }
        // default:
        drawWin('一般般 so so');

    }
    draw(){
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, 60, cvs.clientHeight);
        this.logic();
    }
}
let endState = new End();

function logic(){
    switch(state){
        case ST.START:
            startState.logic();
            break;
        case ST.PLAY:
            playState.logic();
            break;
        case ST.END:
            endState.logic();
            break;
    }
}


function draw(){
    logic(); // call the global logic
    switch(state){
        case ST.CHOOSE:
            chooseState.draw();
            break;
        case ST.START:
            startState.draw();
            break;
        case ST.PLAY:
            playState.draw();
            break;
        case ST.END:
            endState.draw();
            break;
    }


    // TODO if raf != undefined, cancel
    if (raf != undefined) {
        window.cancelAnimationFrame(raf);
    }
    raf = requestAnimationFrame(draw);
}

function drawWin(x){
    ctx.fillStyle = 'red';
    ctx.font = '64px courier';
    ctx.fillText(x, 500, 200)
}

/**
 * 
 * @param {MouseEvent} event 
 */
function onClick(event){
    let x, y;
    x = event.offsetX;
    y = event.offsetY;
    // console.log('mouse x, y = ', x, y);
    switch(state){
        case ST.CHOOSE:
            chooseState.onClick(x, y);
            break;
        case ST.START:
            startState.onClick(x, y);
            break;
        case ST.PLAY:
            playState.onClick(x, y);
            break;
    }
}

function initMouseEvent(){
    cvs.addEventListener("click",onClick);
}

initMouseEvent();
raf = requestAnimationFrame(draw);
